home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / ohlutil.zip / MKDIR.C < prev    next >
C/C++ Source or Header  |  1990-06-22  |  5KB  |  209 lines

  1. /* mkdir -- make directories
  2.    Copyright (C) 1990 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 1, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* Usage: mkdir [-p] [-m mode] [+path] [+mode mode] dir...
  19.  
  20.    Options:
  21.    -p, +path        Ensure that the given path(s) exist:
  22.             Make any missing parent directories for each argument.
  23.             Parent dirs default to umask modified by `u+wx'.
  24.             Do not consider an argument directory that already
  25.             exists to be an error.
  26.    -m, +mode mode    Set the mode of created directories to `mode', which is
  27.             symbolic as in chmod and uses the umask as a point of
  28.             departure.
  29.  
  30.    David MacKenzie <djm@ai.mit.edu>  */
  31.  
  32. #include <stdio.h>
  33. #include <sys/types.h>
  34. #include "system.h"
  35. #include "getopt.h"
  36. #include "modechange.h"
  37.  
  38. #ifdef STDC_HEADERS
  39. #include <errno.h>
  40. #include <stdlib.h>
  41. #else
  42. extern int errno;
  43. #endif
  44.  
  45. int make_path ();
  46. void error ();
  47. void strip_trailing_slashes ();
  48. void usage ();
  49.  
  50. /* If nonzero, ensure that a path exists.  */
  51. int path_mode;
  52.  
  53. /* The name this program was run with. */
  54. char *program_name;
  55.  
  56. struct option longopts[] =
  57. {
  58.   {"mode", 1, NULL, 'm'},
  59.   {"path", 0, &path_mode, 1},
  60.   {NULL, 0, NULL, 0}
  61. };
  62.  
  63. void
  64. main (argc, argv)
  65.      int argc;
  66.      char **argv;
  67. {
  68.   unsigned short newmode;
  69.   unsigned short parent_mode;
  70.   struct mode_change *change;
  71.   char *symbolic_mode;
  72.   int errors = 0;
  73.   int optc;
  74.   int ind;
  75.  
  76.   program_name = argv[0];
  77.   path_mode = 0;
  78.   symbolic_mode = NULL;
  79.  
  80.   while ((optc = getopt_long (argc, argv, "pm:", longopts, &ind)) != EOF)
  81.     {
  82.       if (optc == 0 && longopts[ind].flag == 0)
  83.     optc = longopts[ind].val;
  84.       switch (optc)
  85.     {
  86.     case 0:            /* Long option. */
  87.       break;
  88.     case 'p':
  89.       path_mode = 1;
  90.       break;
  91.     case 'm':
  92.       symbolic_mode = optarg;
  93.       break;
  94.     default:
  95.       usage ();
  96.     }
  97.     }
  98.  
  99.   if (optind == argc)
  100.     usage ();
  101.   
  102.   newmode = 0777 & ~umask (0);
  103.   parent_mode = newmode | 0300;    /* u+wx */
  104.   if (symbolic_mode)
  105.     {
  106.       change = mode_compile (symbolic_mode, MODE_MASK_EQUALS | MODE_MASK_PLUS);
  107.       if (change == MODE_INVALID)
  108.     error (1, 0, "invalid mode");
  109.       else if (change == MODE_MEMORY_EXHAUSTED)
  110.     error (1, 0, "virtual memory exhausted");
  111.       newmode = mode_adjust (newmode, change);
  112.     }
  113.  
  114.   for (; optind < argc; ++optind)
  115.     {
  116.       strip_trailing_slashes (argv[optind]);
  117.       if (path_mode)
  118.     errors |= make_path (argv[optind], newmode, parent_mode);
  119.       else if (mkdir (argv[optind], newmode))
  120.     {
  121.       error (0, errno, "cannot make directory `%s'", argv[optind]);
  122.       errors = 1;
  123.     }
  124.     }
  125.  
  126.   exit (errors);
  127. }
  128.  
  129. /* Make sure directory `path' and all leading directories exist,
  130.    and give it permission mode `mode'.
  131.    If any leading directories are created, give them permission
  132.    mode `parent_mode'.
  133.    Return 0 if successful, 1 if errors occur. */
  134.  
  135. int
  136. make_path (path, mode, parent_mode)
  137.      char *path;
  138.      unsigned short mode;
  139.      unsigned short parent_mode;
  140. {
  141.   char *slash;
  142.   struct stat stats;
  143.  
  144.   if (stat (path, &stats))
  145.     {
  146.       slash = path;
  147.       while (*slash == '/')
  148.     slash++;
  149.       while (slash = index (slash, '/'))
  150.     {
  151.       *slash = 0;
  152.       if (stat (path, &stats))
  153.         {
  154.           if (mkdir (path, parent_mode))
  155.         {
  156.           error (0, errno, "cannot make directory `%s'", path);
  157.           return 1;
  158.         }
  159.         }
  160.       else if ((stats.st_mode & S_IFMT) != S_IFDIR)
  161.         {
  162.           error (0, 0, "`%s' is not a directory", path);
  163.           return 1;
  164.         }
  165.       *slash++ = '/';
  166.     }
  167.  
  168.       if (mkdir (path, mode))
  169.     {
  170.       error (0, errno, "cannot make directory `%s'", path);
  171.       return 1;
  172.     }
  173.     }
  174.   else if ((stats.st_mode & S_IFMT) != S_IFDIR)
  175.     {
  176.       error (0, 0, "`%s' is not a directory", path);
  177.       return 1;
  178.     }
  179.   else if (chmod (path, mode))
  180.     {
  181.       error (0, errno, "cannot change mode of `%s'", path);
  182.       return 1;
  183.     }
  184.   return 0;
  185. }
  186.  
  187. /* Remove trailing slashes from PATH; they cause some system calls to fail. */
  188.  
  189. void
  190. strip_trailing_slashes (path)
  191.      char *path;
  192. {
  193.   int last;
  194.  
  195.   last = strlen (path) - 1;
  196.   while (last > 0 && path[last] == '/')
  197.     path[last--] = '\0';
  198. }
  199.  
  200. void
  201. usage ()
  202. {
  203.   fprintf (stderr, "\
  204. Usage: %s [-p] [-m mode] [+path] [+mode mode] dir...\n",
  205.        program_name);
  206.   exit (1);
  207. }
  208.  
  209.